/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package aprendizajePorRefuerzo.politica;

import aprendizajePorRefuerzo.accion.Accion;
import aprendizajePorRefuerzo.estado.Estado;
import aprendizajePorRefuerzo.funcionQ.Q;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 *
 * @author Fernando Sorzana
 */
public class EpsilonGreedy implements Politica{
    
    private double epsilon;
    
    private Random random;

    public EpsilonGreedy(double epsilon) {
        this.epsilon = epsilon;
        this.random = new Random(new Date().getTime());
    }

    public double getEpsilon() {
        return epsilon;
    }

    public void setEpsilon(double epsilon) {
        this.epsilon = epsilon;
    }

    @Override
    public Accion tomarAccion(Estado estado, Q funcionQ, List<Accion> accionesPosibles) {
        double valor = random.nextDouble();
        if (valor < epsilon){
            return explorar(estado, funcionQ, accionesPosibles);
        } else {
            return tomarMejorAccion(estado, funcionQ, accionesPosibles);
        }
    }
    
    private Accion tomarMejorAccion(Estado estado, Q funcionQ, List<Accion> accionesPosibles) {
        List<Accion> mejoresAcciones = new ArrayList<Accion>();
        Accion maxima = accionesPosibles.get(0);
        mejoresAcciones.add(maxima);
        for (Accion a : accionesPosibles){
            if (funcionQ.getValor(estado, a)>funcionQ.getValor(estado, maxima)){
                maxima = a;
                mejoresAcciones.clear();
                mejoresAcciones.add(a);
            } else if (funcionQ.getValor(estado, a)==funcionQ.getValor(estado, maxima)){
                mejoresAcciones.add(a);
            }
        }
        maxima = mejoresAcciones.get(random.nextInt(mejoresAcciones.size()));
        return maxima;
    }
    
    private Accion explorar(Estado estado, Q funcionQ, List<Accion> accionesPosibles){
        List<Accion> mejoresAcciones = new ArrayList<Accion>();
        List<Accion> otrasAcciones = new ArrayList<Accion>();
        Accion maxima = accionesPosibles.get(0);
        mejoresAcciones.add(maxima);
        for (Accion a : accionesPosibles){
            if (funcionQ.getValor(estado, a)>funcionQ.getValor(estado, maxima)){
                maxima = a;
                for (Accion otra : mejoresAcciones){
                    otrasAcciones.add(otra);
                }
                mejoresAcciones.clear();
                mejoresAcciones.add(a);
            } else if (funcionQ.getValor(estado, a)==funcionQ.getValor(estado, maxima)){
                mejoresAcciones.add(a);
            } else {
                otrasAcciones.add(a);
            }
        }
        if (otrasAcciones.size() > 0){
            maxima = otrasAcciones.get(random.nextInt(otrasAcciones.size()));
        } else {
            maxima = mejoresAcciones.get(random.nextInt(mejoresAcciones.size()));
        }
        return maxima;
    }

    @Override
    public String toString() {
        return "Epsilon Greedy";
    }
    
}
